/********************************************************************/
/*          main.c                                                  */
/*            multi_boot (Multi-play Boot Sample) Main              */
/*                                                                  */
/*          Copyright (C) 1999-2001 NINTENDO Co.,Ltd.               */
/********************************************************************/
//#define CODE32
#include "MultiBoot.h"
#include "MultiSio.h"
#include "types.h"
#include "data.h"


/*-------------------- Global Variable  ----------------------------*/

extern u16      Cont, Trg;                  // Key Input

extern u32      IntrMainBuf[0x100];         // Interrupt Main Routine Buffer

extern u16      BgBak[32*32];               // BG  Backup
extern OamData  OamBak[128];                // OAM Backup


MultiBootParam  multiboot_status;
u8             *demo_bin_start;  // Start address of client program to download
u32             demo_bin_length; // Size of client program to download
int             frame_retval;

const u8 * const BgScDatap_ID[] = {"", "2P", "3P", "4P", };

/*---------------------- Subroutine        -----------------------------*/

extern void DemoMain(void);
extern void KeyRead(void);

void BgScSet(u8 *Srcp, u16 *Destp, u8 PlttNo);


/*------------------------------------------------------------------*/
/*                      Interrupt Table                             */
/*------------------------------------------------------------------*/

extern IntrFuncp IntrTable[13];
extern IntrFuncp IntrTableBuf[13];


/*==================================================================*/
/*                      Main Routine                                */
/*==================================================================*/
extern void intr_main(void);

extern u8 _binary_client_bin_start[], _binary_client_bin_end[]; // Define with client.o

void AgbMain(void)
{
    s32    i;
    char  *StrTmp;
    char   StrTmpBuf[64];

    *(vu16 *)REG_WAITCNT = CST_ROM0_1ST_3WAIT | CST_ROM0_2ND_1WAIT
                         | CST_PREFETCH_ENABLE;            // 3-1 Wait Access Setting

    DmaClear(3, 0,   EX_WRAM,  EX_WRAM_SIZE,            32);// Clear CPU External Work RAM
    DmaClear(3, 0,   CPU_WRAM, CPU_WRAM_SIZE - 0x200,   32);// Clear CPU Internal Work RAM
//  DmaClear(3, 0,   VRAM,     VRAM_SIZE,               32);// Clear VRAM
//  DmaClear(3, 160, OAM,      OAM_SIZE,                32);// Clear OAM
//  DmaClear(3, 0,   PLTT,     PLTT_SIZE,               32);// Clear Palette

    DmaCopy(3, IntrTable, IntrTableBuf,sizeof(IntrTableBuf),32);// Set Interrupt Table
    DmaCopy(3, intr_main, IntrMainBuf, sizeof(IntrMainBuf), 32);// Set Interrupt Main Routine
    *(vu32 *)INTR_VECTOR_BUF = (vu32 )IntrMainBuf;

    DmaArrayCopy(3, CharData_Sample,    BG_VRAM+0x8000, 32);// Set BG Character
    DmaArrayCopy(3, CharData_Sample,    OBJ_MODE0_VRAM, 32);// Set OBJ Character
    DmaArrayCopy(3, PlttData_Sample,    BG_PLTT,        32);//  Set BG Palette
    DmaArrayCopy(3, PlttData_Sample,    OBJ_PLTT,       32);// Set OBJ Palette

    DmaArrayCopy(3, BgScData_Sample,    BgBak,          32);// Set BG Screen

    DmaArrayClear(3,160,                OamBak,         32);// Undisplayed OBJ moves outside screen-

    *(vu16 *)REG_BG0CNT =                                   // Set BG Control
            BG_COLOR_16 | BG_SCREEN_SIZE_0 | BG_PRIORITY_0
            | 0 << BG_SCREEN_BASE_SHIFT | 2 << BG_CHAR_BASE_SHIFT ;
    *(vu16 *)REG_BG1CNT =
            BG_COLOR_16 | BG_SCREEN_SIZE_0 | BG_PRIORITY_0
            | 1 << BG_SCREEN_BASE_SHIFT | 2 << BG_CHAR_BASE_SHIFT ;

    *(vu16 *)REG_IE    = V_BLANK_INTR_FLAG            // Enable V-Blank Interrupt
                       | CASSETTE_INTR_FLAG;          // Enbale Game Pak Interrupt
    *(vu16 *)REG_STAT  = STAT_V_BLANK_IF_ENABLE;
    *(vu16 *)REG_IME   = 1;                                 // Set IME

    *(vu16 *)REG_DISPCNT = DISP_MODE_0 | DISP_BG0_ON; // LCDC ON

    demo_bin_start = _binary_client_bin_start;
    demo_bin_length = (u32)_binary_client_bin_end - (u32)_binary_client_bin_start;

    multiboot_status.masterp = demo_bin_start;
    multiboot_status.server_type = MULTIBOOT_SERVER_TYPE_NORMAL;
    MultiBootInit(&multiboot_status);               // Multi-play boot Initialization

    while (1) {
        VBlankIntrWait();                           // Wait for V-Blank Interrupt End

        for (i = 1; i < 4; i++) {
            if ((multiboot_status.response_bit & (1 << i)) == 0) {
                        StrTmp = "Not connected";
            } else {
                if ((multiboot_status.client_bit & (1 << i)) == 0)
                        StrTmp = "Checking...  ";
                else    StrTmp = "Ready        ";
            }
            BgScSet((u8 *)BgScDatap_ID[i], &BgBak[32*(5+i)+ 7], 3);
            BgScSet(StrTmp,                &BgBak[32*(5+i)+10], 3);
        }

        if (multiboot_status.client_bit  & 0xe) {
            switch (multiboot_status.probe_count) {
                case 0x00: StrTmp = "PUSH START      ";   break;
                case 0xd1: StrTmp = "NOW SENDING...  ";   break;
                default:   StrTmp = "                ";   break;
            }
            if (multiboot_status.probe_count >= 0xe0)
                           StrTmp = "BOOT CHECKING...";
        } else             StrTmp = "                ";
        BgScSet(StrTmp, &((u16 *)BG_VRAM)[32*11+7], 1);

        KeyRead();

        if (Trg & START_BUTTON
            && multiboot_status.probe_count == 0
            && multiboot_status.client_bit != 0) {
            MultiBootStartMaster(&multiboot_status,     // Start Multi-play boot transfer
                                 &demo_bin_start[MULTIBOOT_HEADER_SIZE],
                                  demo_bin_length - MULTIBOOT_HEADER_SIZE,
                                  4, 1);
        }
        frame_retval = MultiBootMain(&multiboot_status);// Multi-play Boot Main
        if (MultiBootCheckComplete(&multiboot_status))  // Check for Multi-play boot transfer completed
                break;
    }

    *(vu16 *)REG_IME = 0;                           // Reset IME
    *(vu16 *)REG_STAT = 0;
    *(vu16 *)REG_IE  = 0;                           // Reset IE
    *(vu16 *)REG_IF  = 0xffff;                      // Reset Interrupt Request
    *(vu16 *)REG_DISPCNT = DISP_LCDC_OFF;

    DemoMain();                                     // Run Demo Program
}


